<?php

/**
 * SessionAuth
 *
 * @author vbolshov
 */

namespace km\auth;

use km\exception\HeadersSentException;
use \Km;

class SessionAuth {
	/**
	 * Check identity. Lookup for $_SESSION['user'] and return it. If not found, returns FALSE.
	 *
	 * @param Closure $checker when specified, will be called with $_SESSION['user'] as argument,
	 * to provide additional check. Should return a boolean.
	 * @return either contents of $_SESSION['user'] or bool FALSE
	 * @throws HeadersSentException
	 */
	function checkIdentity($checker = null) {
		
		$sname = session_name();
		if ((! $session_started = isset($_COOKIE[$sname])) && 
			(ini_get('session.use_trans_sid'))) {

			$session_started = isset($_GET[$sname]) || isset($_POST[$sname]);
		}
		
		if (! $session_started) {
			return false;
		}
		
		if (headers_sent()) {
			throw new HeadersSentException();
		}
		
		@session_start();// suppress possible "session already started" error
		
		if (! isset($_SESSION['user'])) {
			return false;
		}
		
		if ((! isset($_SESSION['session_ip'])) || 
			($_SESSION['session_ip'] != $_SERVER['REMOTE_ADDR']))
		{// bind session to ip for better security
			$_SESSION = array();
			return false;
		}
		
		if ($checker) {
			if (Km::toClosure($checker)->__invoke($_SESSION['user'])) {
				return $_SESSION['user'];
			} else {
				$this->close();
				return false;
			}
		}
		
		return $_SESSION['user'];
	}
	/**
	 * setup session using a custom callback $identifier, which will be called with 
	 * arguments ($username, $password).
	 * If the callback returns any value that evaluates to FALSE - setup() returns FALSE.
	 * In other case, setup() returns that returned value and writes it to $_SESSION['user']
	 *
	 * @param string $username
	 * @param string $password
	 * @param Closure $identifier
	 */
	function setup($username, $password, $identifier) {
		if ($user = Km::toClosure($identifier)->__invoke($username, $password)) {
			@session_start();// suppress possible "session already started" error
			$_SESSION['session_ip']		= $_SERVER['REMOTE_ADDR'];
			return $_SESSION['user']	= $user;
		} else {
			return false;
		}
	}
	/**
	 * Update user data stored in session
	 * @param array $updatedUserData
	 */
	function update(array $updatedUserData)
	{
		if (@$_SESSION['user']) {
			$_SESSION['user'] = array_merge($_SESSION['user'], $updatedUserData);
		}
	}
	/**
	 * Close session
	 */
	function close() {
		@session_destroy();
		setcookie(
			session_name(), 
			"", 
			time() - 100000, 
			ini_get('session.cookie_path'), 
			ini_get('session.cookie_domain'), 
			ini_get('session.cookie_secure')
		);
	}
}